// 'use strict';
// Object.seal() 封闭对象 密闭对象

// Object.freeze 不可修改、不可扩展、不可删除

// Object.isSealed() 判断一个对象是否被密封。


// const obj = {
//   a: 1,
//   b: 2
// }

// Object.prototype.c = 3;

// const newObj = Object.seal(obj);
// console.log(newObj === obj); // 同一个引用 true

// const res = Object.isSealed(obj);
// console.log(res); // true

// console.log(obj.a); // 可读
// obj.a = 111;
// console.log(obj); // 可修改
// delete obj.b;
// console.log(obj); // 不可删除
// obj.d = 4;
// console.log(obj); // 不可扩展

/**
 * use strict模式下
 * 
 * 删除、扩展操作会抛出错误 throws a TypeError
 */


// obj.__proto__.c = 333;
// console.log(obj); // 可修改
// Object.prototype.c = 444;
// console.log(obj); // 可修改

// obj.__proto__ = {} // 会抛出错误不可扩展 is not extensible
// console.log(obj);

// obj.__proto__ = {
//   a: 1,
//   b: 2,
//   c: 3
// }
// console.log(obj);

// Object.prototype = {
//   a: 1,
//   b: 2,
//   c: 3
// }
// console.log(obj);



// const obj = {
//   a: 1
// }

// Object.seal(obj);

// Cannot redefine property: a 不可重新定义
// Object.defineProperty(obj, 'a', {
//   get() {
//     return 111;
//   }
// })

// Object.defineProperty(obj, 'a', {
//   value: 111
// })
// console.log(obj); // 可修改


// Cannot define property b, object is not extensible
// 不可扩展
// Object.defineProperty(obj, 'b', {
//   // get() {
//   //   return 222;
//   // }
//   value: 222
// })


// const res = Object.seal(true);
// console.log(res); // 返回本身

// 在ES5环境下 如果这个方法的参数不是一个（原始）对象会抛出错误 TypeError
// 在ES2015(ES6)中，非对象参数将被视为已被密封的普通对象，会直接返回它



// const arr = [1, 2, 3];
// const arr = {
//   '0': 1,
//   '1': 2,
//   '2': 3,
//   // '3': 4
//   'length': 3
// }

// Object.seal(arr);
// console.log(arr[1]);
// delete arr[0];
// console.log(arr); // (严格模式下也)不会抛出错误(静默失败) 不可删除
// arr[0] = 111;
// console.log(arr); // 不会抛出错误 可修改
// arr.push(4); // 会抛出错误 不可扩展
// Cannot add property 3, object is not extensible




const obj = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: {
      f: 4
    }
  }
}

// Object.seal(obj); // 浅封闭

// obj.y = 'yyy';   // 不可扩展
// obj.c.x = 'xxx'; // 可扩展
// delete obj.c.e.f // 可删除
// console.log(obj);



// 实现一个 deepSeal 深封闭方法 (递归思想)

Object.deepSeal = function (obj) {
  // 获取键(keys)
  // 使用Object.keys 获取不到 不可枚举的对象的keys
  const _keys = Object.getOwnPropertyNames(obj);

  if (_keys.length) {
    _keys.forEach(k => {
      const _v = obj[k];
      
      if (typeof _v === 'object' && _v !== null) {
        Object.deepSeal(_v);
      }
    })
  }

  return Object.seal(obj);
}

Object.deepSeal(obj); // 浅封闭

obj.y = 'yyy';   // 不可扩展
obj.c.x = 'xxx'; // 不可扩展
delete obj.c.e.f // 不可删除
console.log(obj);